﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Routing;
using MvcPatch.Routing;

namespace MvcShop.Extensions
{
    public static class RouteCollectionExtensions
    {
        public static void MapDomain(
            this RouteCollection routeCollection,
            string prefix,
            string pattern,
            Action<IDictionary<string, RouteBase>> routeCollector)
        {
            routeCollection.MapDomain(prefix, pattern, null, null, routeCollector);
        }

        public static void MapDomain(
            this RouteCollection routeCollection,
            string prefix,
            string pattern,
            object defaults,
            Action<IDictionary<string, RouteBase>> routeCollector)
        {
            routeCollection.MapDomain(prefix, pattern, defaults, null, routeCollector);
        }

        public static void MapDomain(
            this RouteCollection routeCollection,
            string prefix,
            string pattern,
            object defaults,
            object constraints,
            Action<IDictionary<string, RouteBase>> routeCollector)
        {
            var innerRoutes = new Dictionary<string, RouteBase>(StringComparer.OrdinalIgnoreCase);
            routeCollector(innerRoutes);

            prefix = String.IsNullOrEmpty(prefix) ? "" : prefix + ".";
            foreach (var pair in innerRoutes)
            {
                routeCollection.Add(prefix + pair.Key, pair.Value.WithDomain(pattern, defaults, constraints));
            }
        }

        public static VirtualPathData GetVirtualPathEx(this RouteCollection routeCollection, RequestContext requestContext, string routeName, RouteValueDictionary values)
        {
            var route = routeCollection[routeName];
            if (route == null) return null;

            return routeCollection.GetVirtualPathEx(route, requestContext, values);
        }

        public static VirtualPathData GetVirtualPathEx(this RouteCollection routeCollection, RequestContext requestContext, RouteValueDictionary values)
        {
            return routeCollection.GetVirtualPathEx(null, requestContext, values);
        }

        private static VirtualPathData GetVirtualPathEx(this RouteCollection routeCollection, RouteBase route, RequestContext requestContext, RouteValueDictionary values)
        {
            var path = route == null ? routeCollection.GetVirtualPathExBase(requestContext, values) : route.GetVirtualPath(requestContext, values);
            if (path == null) return null;

            if (WithScheme(path.VirtualPath)) return path;

            path.VirtualPath = GetUrlWithApplicationPath(requestContext, path.VirtualPath);
            return path;
        }

        private static string GetUrlWithApplicationPath(RequestContext requestContext, string virtualPath)
        {
            string appPath = requestContext.HttpContext.Request.ApplicationPath ?? string.Empty;
            if (!appPath.EndsWith("/", StringComparison.OrdinalIgnoreCase))
            {
                appPath = appPath + "/";
            }

            return appPath + virtualPath;
        }

        private static string Merge(RequestContext requestContext, string domain, string virtualPath)
        {
            var url = requestContext.HttpContext.Request.Url;
            var currentDomain = url.Scheme + "://" + url.Host;
            if (currentDomain.Equals(domain, StringComparison.OrdinalIgnoreCase))
            {
                return virtualPath;
            }

            string appPath = requestContext.HttpContext.Request.ApplicationPath ?? string.Empty;
            if (!appPath.EndsWith("/", StringComparison.OrdinalIgnoreCase))
            {
                appPath += "/";
            }

            return domain + appPath + virtualPath;
        }

        private static bool WithScheme(string url)
        {
            return url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ||
                url.StartsWith("https://", StringComparison.OrdinalIgnoreCase);
        }

        private static VirtualPathData GetVirtualPathExBase(this RouteCollection routeCollection, RequestContext requestContext, RouteValueDictionary values)
        {
            foreach (var route in routeCollection)
            {
                var path = route.GetVirtualPath(requestContext, values);
                if (path != null) return path;
            }

            return null;
        }
    }
}
